package net.mycrub.bitwise.ocr.training;

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.font.TextAttribute;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;
import java.text.AttributedString;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;

public class DigitSampleGenerator {

    private int width;
    private int height;
    private AffineTransform trans = new AffineTransform();
    
    // FIXME The fonts that exist on my computer, and that can write the numbers
    private static String[] fonts = { "Andalus", "Arial", "Arial Gras",
            "Calibri Bold", "Calibri Bold Italic", "Cambria Italic",
            "Cambria Math", "Candara Bold Italic", "Century Gothic Italique",
            "Consolas Bold", "Constantia Bold", "Corbel Italic",
            "Dialog.bolditalic", "Dotum", "Engravers MT", "Eurostile",
            "Felix Titling", "Franklin Gothic Heavy Italique", "Georgia Gras",
            "Georgia Italique", "Gisha", "HGHangle", "HGHeiseiMinchotaiW3",
            "HGMinchoL", "HGP-AGothic2-Latin1K", "HGSHeiseiKakugothictaiW9",
            "HGSHeiseiMinchotaiW9", "Impact", "Iskoola Pota", "Kalinga Bold",
            "Khmer UI", "Latha", "Leelawadee", "Levenim MT Bold",
            "Lucida Bright Regular", "Lucida Sans Typewriter Bold",
            "Lucida Sans Typewriter Regular", "Malgun Gothic", "Mangal",
            "Meiryo Gras", "Meiryo UI Italique", "Microsoft JhengHei",
            "Microsoft PhagsPa", "Monospaced.bold", "Monospaced.bolditalic",
            "MS Gothic", "MS UI Gothic", "Palatino Linotype Italique",
            "SansSerif.bolditalic", "Segoe Print Bold", "Segoe UI Gras",
            "Shruti Bold", "Simplified Arabic Fixed", "Sylfaen",
            "Times New Roman", "Times New Roman Italic",
            "Traditional Arabic Bold", "Verdana", "Vrinda Bold" };

    public static void main(String[] args) {
        DigitSampleGenerator gen = new DigitSampleGenerator(20, 20);
        for (int i = 0; i < 1000; i++) {
            gen.generateInDirectory(i % 10, args[0]);
        }
    }

    public DigitSampleGenerator(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public void generateInDirectory(int value, String directory) {
        RenderedImage image = createImage(value);
        String dir = directory + "/" + value;
        new File(dir).mkdirs();
        File file = new File(dir + "/" + System.nanoTime() + ".png");
        try {
            ImageIO.write(image, "png", file);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public BufferedImage createImage(int value) {
        BufferedImage bufferedImage = new BufferedImage(width * 10, height * 10, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = bufferedImage.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setColor(Color.getHSBColor((float) Math.random(), 
                (float) Math.random() * .05f, 1 - (float) Math.random() * .2f));
        g2d.fillRect(0, 0, width * 10, height * 10);

        Font font = getRandomFont(value);
        FontMetrics metrics = g2d.getFontMetrics(font);
        String sv = Integer.toString(value);
        AttributedString text = new AttributedString(sv);
        text.addAttribute(TextAttribute.FOREGROUND, Color.getHSBColor(
                (float) Math.random(), (float) Math.random() * .05f,
                (float) Math.random() * .5f));
        text.addAttribute(TextAttribute.FONT, font);
        int w = metrics.stringWidth(sv);
        int h = metrics.getAscent() + metrics.getDescent();

        trans.setToIdentity();
        trans.scale((float) width / (float) w * (.9 - Math.random() * .1) * 9,
                (float) height / (float) h * (.9 - Math.random() * .1) * 9);
        trans.rotate((Math.random() - .6) * .3);

        font = font.deriveFont(trans);
        text.addAttribute(TextAttribute.FONT, font);
        metrics = g2d.getFontMetrics(font);
        w = metrics.stringWidth(sv);
        h = metrics.getAscent();

        int dx = width * 10 - w;
        int dy = height * 10 - h;

        g2d.setFont(font);
        g2d.drawString(text.getIterator(), dx * (float) Math.random(), height
                * 10 - dy * (float) Math.random());

        g2d.dispose();
        return getScaledInstance(bufferedImage, width, height, true);
    }

    private Font getRandomFont(int v) {
        String f = fonts[(int) (Math.random() * fonts.length)];
        return Font.decode(f);
    }

    public BufferedImage getScaledInstance(BufferedImage img, int targetWidth,
            int targetHeight, boolean higherQuality) {
        int type = (img.getTransparency() == Transparency.OPAQUE) ? BufferedImage.TYPE_INT_RGB
                : BufferedImage.TYPE_INT_ARGB;
        BufferedImage ret = img;
        int w, h;
        if (higherQuality) {
            w = img.getWidth();
            h = img.getHeight();
        } else {
            return toBufferedImage(img.getScaledInstance(targetWidth, -1,
                    BufferedImage.SCALE_SMOOTH));
        }

        do {
            if (higherQuality && w > targetWidth) {
                w /= 2;
                if (w < targetWidth) {
                    w = targetWidth;
                }
            }

            if (higherQuality && h > targetHeight) {
                h /= 2;
                if (h < targetHeight) {
                    h = targetHeight;
                }
            }

            BufferedImage tmp = new BufferedImage(w, h, type);
            Graphics2D g2 = tmp.createGraphics();
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                    RenderingHints.VALUE_INTERPOLATION_BICUBIC);
            g2.drawImage(ret, 0, 0, w, h, null);
            g2.dispose();

            ret = tmp;
        } while (w != targetWidth || h != targetHeight);

        return ret;
    }

    public BufferedImage toBufferedImage(Image image) {
        if (image instanceof BufferedImage) {
            return (BufferedImage) image;
        }
        image = new ImageIcon(image).getImage();

        BufferedImage bimage = null;
        GraphicsEnvironment ge = GraphicsEnvironment
                .getLocalGraphicsEnvironment();
        try {
            int transparency = Transparency.OPAQUE;
            GraphicsDevice gs = ge.getDefaultScreenDevice();
            GraphicsConfiguration gc = gs.getDefaultConfiguration();
            bimage = gc.createCompatibleImage(image.getWidth(null), image
                    .getHeight(null), transparency);
        } catch (HeadlessException e) {
            e.printStackTrace();
        }

        if (bimage == null) {
            int type = BufferedImage.TYPE_INT_RGB;
            bimage = new BufferedImage(image.getWidth(null), image
                    .getHeight(null), type);
        }
        Graphics g = bimage.createGraphics();
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return bimage;
    }

}
